import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Iterator;

public class SymbolTable {
	private SymbolTable singleton = null;
	private ArrayList<Hashtable<String,String>> symboltbls;
	//To generate IDs
	private int count;

	public SymbolTable() {
		if (singleton == null) {
			symboltbls = new ArrayList<Hashtable<String,String>>();		
			this.singleton = this;
			this.count = 0;
			enterScope();
		}
	}

	public void enterScope() {
		Hashtable<String,String> currScope = new Hashtable<String,String>();
		symboltbls.add(0,currScope);
	}

	public void leaveScope() throws Exception {
		if (symboltbls.isEmpty()) 
			throw new Exception("You are not in a scope! There is something wrong...");
		symboltbls.remove(0);
	}

	public String getID(String varName) throws NotDefinedVariableException {
		for (Hashtable<String,String> it : symboltbls){
			if (it.containsKey(varName))
				return it.get(varName);
		}
		throw new NotDefinedVariableException("Error: the variable "+varName+" has not been defined.");
	}

	public boolean register(String varName) throws Exception {
		Iterator<Hashtable<String,String>> it = symboltbls.iterator();
		while (it.hasNext()) {
			Hashtable<String,String> scope = it.next();
			if (scope.containsKey(varName))
				throw new Exception("Error: the variable "+varName+" has been " +
				"already defined.");
		}
		Hashtable<String,String> topScope = symboltbls.get(0);
		topScope.put(varName, generateNewID());
		return true;
	}

	private String generateNewID() {
		return "var_"+count++;
	}

	public static void main(String[] args) throws Exception {
		Integer i = 0;
		SymbolTable st = new SymbolTable();
		while (i++ < 5){
			st.enterScope();
			st.register(i.toString());			
		}
		i = 0;
		while (i++ < 5)
			System.out.println(st.getID(i.toString()));
	}
}
